import ast
import json
from datetime import datetime
from textwrap import dedent

import pandas as pd
from typing import List

from app.agent.quant_params import QuantParams


def z_score_normalize(
        series: pd.Series,
        window: int = 60,  # 滚动窗口周期（交易日）
        clip_threshold: float = 3,  # 异常值截断阈值
        ddof: int = 0,  # 自由度调整（0=总体标准差，1=样本标准差）
        min_periods: int = 20  # 最小计算窗口（避免初期数据不足）
) -> pd.Series:
    """
    金融时间序列安全的滚动z-score标准化
    """
    # 滚动均值和标准差
    rolling_mean = series.rolling(window=window, min_periods=min_periods).mean()
    rolling_std = series.rolling(window=window, min_periods=min_periods).std(ddof=ddof)

    # 计算z-score并截断异常值
    z_score = (series - rolling_mean) / rolling_std
    return z_score.clip(lower=-clip_threshold, upper=clip_threshold)



def extract_json_string(text):
    # 查找第一个三引号的起始位置
    start_index = text.find("```")
    if start_index == -1:
        return None
    # 从第一个三引号之后开始查找第二个三引号的位置
    end_index = text.find("```", start_index + 3)
    if end_index == -1:
        return None
    # 提取两个三引号之间的字符串
    json_str = text[start_index + 3:end_index].replace("json","")
    print("打印分割完成的结果，text="+json_str)
    try:
        # 尝试解析提取的字符串为 JSON 对象
        return json.loads(json_str)
    except json.JSONDecodeError:
        # 如果解析失败，说明提取的字符串不是有效的 JSON 格式
        return None


def parse_factors_response(llm_response):
    candidate_factors = {}
    data = extract_json_string(llm_response)
    print(data)
    for item in data:
        candidate_factors[item["因子名称"]]=item["因子计算方法"]
    print(candidate_factors)
    return candidate_factors

def parse_evaluate_response(llm_response):
    data = extract_json_string(llm_response)
    # print("=======parse_evaluate_response=========")
    # print(data)
    # data["预期收益"] = validate_factor()
    return data


import pandas as pd
import numpy as np


def handle_missing_data(data: pd.DataFrame, method: str = 'ffill') -> pd.DataFrame:
    """
    处理缺失值（以时间序列数据为例）

    参数：
        data: 原始数据（需包含时间索引）
        method:
            'ffill' - 前向填充（默认）
            'interpolate' - 线性插值
            'drop' - 删除缺失行

    返回：
        处理后的DataFrame
    """
    if method == 'ffill':
        return data.ffill().bfill()  # 先向前填充再向后填充
    elif method == 'interpolate':
        return data.interpolate(method='time')  # 按时间索引插值
    elif method == 'drop':
        return data.dropna()
    else:
        raise ValueError("无效的缺失值处理方法")


def detect_duplicates(data: pd.DataFrame) -> dict:
    """
    检测重复数据并返回重复位置

    返回：
        {
            'duplicate_rows': 重复行索引列表,
            'duplicate_rate': 重复率
        }
    """
    duplicated = data.duplicated(keep='first')
    return {
        'duplicate_rows': data.index[duplicated].tolist(),
        'duplicate_rate': duplicated.mean()
    }

"""提示词"""
def build_prompt(params: QuantParams, features: list) -> str:
    base_template = """
    作为专业量化研究员，请为{asset_class_1}交易生成Python因子函数：

    输入数据字段：{features}
    参数约束：
    1. 时间粒度：{time_frame}
    2. 最大回撤：{max_drawdown}
    3. 可用数据源：{data_sources}
    {specific_instructions}

    输出要求：
    - 函数名以factor_开头
    - 返回值为交易信号Series（-1到1之间）
    - 包含详细注释说明逻辑
    """

    specific_rules = {
        "外汇1": """
        外汇特殊要求：
        - 需考虑{currency_pair}的隔夜利息成本
        - 杠杆率限制：{leverage_ratio}倍
        - 整合订单簿L2数据特征
        """,
        "国债2": """
        债券特殊要求：
        - 久期类型：{bond_duration}
        - 信用评级：{credit_rating}
        - 考虑收益率曲线形态变化
        """
    }
    ac = params["asset_class"]
    ac1=ac+'1'
    asset_class = ac
    features = ", ".join(features)
    specific_instructions = str(specific_rules.get(ac1, ""))

    return base_template.format(
        asset_class_1=asset_class,
        features=features,
        specific_instructions=specific_instructions,
        **params
    )


def load_fx_data(pair: str, timeframe: str) -> pd.DataFrame:
    """
    加载模拟外汇市场数据
    包含订单簿L2数据、宏观经济指标和SWIFT结算量

    参数：
        pair: 货币对名称 (如 "EUR/USD")
        timeframe: 时间粒度 ("1分钟", "15分钟"等)

    返回：
        DataFrame 包含以下字段：
        - timestamp: 时间戳
        - open/close/high/low: OHLC价格
        - bid1_qty/ask1_qty: 最优买卖档量
        - bid_ask_spread: 点差(bps)
        - swap_rate: 隔夜利息差
        - swift_volume: SWIFT结算量(百万)
    """
    try:
        # 生成时间序列
        freq_map = {
            "1分钟": "T", "15分钟": "15T",
            "1小时": "H", "日线": "D"
        }
        index = pd.date_range(
            end=datetime.now(),
            periods=1000,
            freq=freq_map.get(timeframe, "H")
        )

        # 生成模拟数据
        np.random.seed(42)
        data = pd.DataFrame(index=index)
        data["open"] = np.random.normal(1.08, 0.002, len(index)).cumsum()
        data["close"] = data["open"] + np.random.normal(0, 0.001, len(index))
        data["high"] = data[["open", "close"]].max(axis=1) + np.random.uniform(0, 0.0005, len(index))
        data["low"] = data[["open", "close"]].min(axis=1) - np.random.uniform(0, 0.0005, len(index))

        # 订单簿数据
        data["bid_qty"] = np.random.randint(1e6, 5e6, len(index))
        data["ask_qty"] = np.random.randint(1e6, 5e6, len(index))
        data["bid_ask_spread"] = np.random.uniform(0.5, 2.5, len(index))

        # 宏观数据
        data["swap_rate"] = np.random.normal(0.002, 0.0005, len(index))
        data["swift_volume"] = np.abs(np.random.normal(500, 200, len(index)))

        return data.round(5)

    except Exception as e:
        print(f"加载外汇数据失败: {str(e)}")
        return pd.DataFrame()


def load_bond_data(duration: str, rating: str) -> pd.DataFrame:
    """
    加载模拟债券市场数据

    参数：
        duration: 久期分类 ("短端(1-3Y)", etc)
        rating: 信用评级 ("AAA", etc)

    返回：
        DataFrame 包含以下字段：
        - date: 日期
        - clean_price: 净价
        - yield: 到期收益率(%)
        - modified_duration: 修正久期
        - convexity: 凸性
        - corporate_spread: 信用利差(bps)
        - policy_sentiment: 政策情绪得分(-1~1)
    """
    try:
        # 生成时间序列
        dates = pd.date_range(end=datetime.now(), periods=500, freq="D")

        # 基础收益率曲线
        base_yield = {
            "短端(1-3Y)": np.random.normal(2.5, 0.3),
            "中端(3-7Y)": np.random.normal(3.2, 0.2),
            "长端(7Y+)": np.random.normal(3.8, 0.4)
        }[duration]

        # 生成数据
        data = pd.DataFrame(index=dates)
        data["clean_price"] = 100 + np.cumsum(np.random.normal(0, 0.1, len(dates)))
        data["yield"] = base_yield + np.random.normal(0, 0.05, len(dates))
        data["modified_duration"] = {
                                        "短端(1-3Y)": 2.5, "中端(3-7Y)": 5.0, "长端(7Y+)": 8.0
                                    }[duration] + np.random.normal(0, 0.1, len(dates))
        data["convexity"] = data["modified_duration"] ** 2 / 100
        data["corporate_spread"] = {
                                       "AAA": 50, "AA+": 80, "AA": 120
                                   }[rating] + np.random.randint(-10, 10, len(dates))
        data["policy_sentiment"] = np.random.uniform(-0.8, 0.8, len(dates))

        return data.round(4)

    except KeyError as ke:
        print(f"无效参数: {str(ke)}")
        return pd.DataFrame()
    except Exception as e:
        print(f"加载债券数据失败: {str(e)}")
        return pd.DataFrame()


def load_metal_data(params: QuantParams) -> pd.DataFrame:
    """
    加载贵金属市场数据（示例实现）
    包含：
    - 价格数据：open, high, low, close, volume
    - 持仓数据：非商业持仓、ETF持有量
    - 宏观数据：美元指数、实际利率
    """
    # 生成示例数据
    dates = pd.date_range(end=pd.Timestamp.today(), periods=1000, freq='D')
    data = pd.DataFrame(index=dates)

    # 价格序列
    np.random.seed(42)
    base_price = 1800 if params['metal_type'] == "黄金" else 25
    data['close'] = base_price + np.cumsum(np.random.normal(0, 0.5, len(dates)))

    # 持仓数据
    data['commercial_oi'] = np.random.randint(1e4, 5e4, len(dates))
    data['etf_holdings'] = np.abs(np.random.normal(1e3, 200, len(dates)))

    # 宏观数据
    data['dxy'] = 90 + np.sin(np.linspace(0, 2 * np.pi, len(dates))) * 5
    data['real_rate'] = np.random.normal(-0.02, 0.01, len(dates))

    return data


def preprocess_metal_data(raw_data: pd.DataFrame) -> pd.DataFrame:
    """贵金属数据预处理"""
    df = raw_data.copy()

    # 生成技术指标
    df['MA20'] = df['close'].rolling(20).mean()
    df['ATR'] = (
        df[['high', 'low', 'close']].apply(
            lambda x: max(x.high - x.low,
                          abs(x.high - x.close.shift()),
                          abs(x.low - x.close.shift())),
            axis=1
        ).rolling(14).mean()
    )

    # 标准化处理
    df['dxy_norm'] = (df['dxy'] - df['dxy'].mean()) / df['dxy'].std()
    df['oi_zscore'] = (df['commercial_oi'] - df['commercial_oi'].mean()) / df['commercial_oi'].std()

    return df.dropna()

import re
from ast import parse, FunctionDef
import inspect


def parse_factors_1(response_text: str) -> list:
    """
    从大模型响应中解析有效的Python因子函数

    参数：
        response_text: 大模型生成的原始文本

    返回：
        合法Python函数名称列表
    """
    try:
        # 提取代码块
        code_blocks = re.findall(r"```python(.*?)```", response_text, re.DOTALL)

        valid_factors = []
        for code in code_blocks:
            try:
                # 语法验证
                parse(code)

                # 提取函数定义
                tree = parse(code)
                for node in tree.body:
                    if isinstance(node, FunctionDef):
                        # 验证函数签名
                        args = inspect.getfullargspec(node)
                        if args.args != ["data"]:
                            continue

                        # 检查返回值注释
                        if not (node.returns and "Series" in node.returns.id):
                            continue

                        valid_factors.append(node.name)

            except SyntaxError:
                continue

        return valid_factors

    except Exception as e:
        print(f"因子解析失败: {str(e)}")
        return []


def parse_factors(response_text: str) -> List[str]:
    """
    从大模型响应中解析有效的Python因子函数（修复版）

    修复要点：
    1. 使用AST模块直接解析函数参数（替代inspect模块）
    2. 处理返回类型注解的多种形式
    3. 增加代码规范化预处理
    """
    valid_factors = []
    factors_names = []

    try:
        # 提取代码块并规范化
        code_blocks = re.findall(r"```python(.*?)```", response_text, re.DOTALL)

        for raw_code in code_blocks:
            try:
                # 预处理代码
                code = dedent(raw_code).strip()
                # if not code.startswith("def "):
                #     continue  # 跳过非函数定义代码
                valid_factors.append(code)
                # 解析AST
                tree = ast.parse(code)

                for node in ast.walk(tree):
                    if isinstance(node, ast.FunctionDef):
                        factors_names.append(node.name)
                #         # 验证参数列表
                #         args = [arg.arg for arg in node.args.args]
                #         if args != ["data"]:
                #             continue
                #
                #         # 验证返回类型注解
                #         return_annotation = None
                #         if node.returns:
                #             # 处理简单类型注解 (pd.Series)
                #             if isinstance(node.returns, ast.Name):
                #                 return_annotation = node.returns.id
                #             # 处理带模块的注解 (pd.Series)
                #             elif isinstance(node.returns, ast.Attribute):
                #                 return_annotation = node.returns.attr
                #             # 处理可选类型注解 (Optional[pd.Series])
                #             elif isinstance(node.returns, ast.Subscript):
                #                 if hasattr(node.returns.value, 'id') and node.returns.value.id == "Optional":
                #                     inner = node.returns.slice
                #                     if isinstance(inner, ast.Name):
                #                         return_annotation = inner.id
                #                     elif isinstance(inner, ast.Attribute):
                #                         return_annotation = inner.attr
                #
                #         if return_annotation and "Series" in return_annotation:
                #             valid_factors.append(node.name)

            except SyntaxError as se:
                print(f"语法错误跳过代码块: {str(se)}")
                continue
            except Exception as e:
                print(f"解析异常: {str(e)}")
                continue

    except Exception as e:
        print(f"全局解析失败: {str(e)}")

    return valid_factors,factors_names

def calculate_max_drawdown(returns: pd.Series) -> float:
    """
    计算收益序列的最大回撤

    参数：
        returns: 收益率序列 (建议使用日收益率)

    返回：
        最大回撤比例 (例如 -0.15 表示15%回撤)
    """
    try:
        if returns.empty or len(returns) < 2:
            return 0.0

        # 计算累积净值
        cumulative = (1 + returns).cumprod()

        # 计算历史最大值
        peak = cumulative.expanding(min_periods=1).max()

        # 计算回撤
        drawdown = (cumulative / peak) - 1

        return round(drawdown.min(), 4)

    except Exception as e:
        print(f"回撤计算错误: {str(e)}")
        return 0.0


def validate_bond_data(df: pd.DataFrame):
    """检查债券价格合理性"""
    if (df['clean_price'] < 50).any():
        raise ValueError("债券净价异常低于面值")


def safe_factor_eval(code: str, data: pd.DataFrame):
    """在隔离环境中执行因子"""
    restricted_globals = {"pd": pd, "np": np}
    local_vars = {"data": data}
    exec(code, restricted_globals, local_vars)
    return local_vars["factor"](data)


from typing import Dict


# 假设从自定义模块导入参数类型


def validate_factor(backtest_report: Dict[str, Dict[str, float]],
                    params: QuantParams) -> bool:
    """
    验证回测结果是否符合资产类别要求

    参数：
        backtest_report: 因子回测报告字典
                        格式：{因子名称: {指标名称: 数值}}
        params: 量化参数字典，必须包含asset_class字段

    返回：
        bool: 是否至少有一个因子通过验证

    异常：
        ValueError: 当参数不合法时抛出
    """
    # 参数合法性检查
    if not backtest_report or not isinstance(backtest_report, dict):
        return False

    if "asset_class" not in params:
        raise ValueError("参数中缺失资产类别(asset_class)")

    asset_class = params["asset_class"]
    valid_assets = ["外汇", "国债", "政策性金融债"]
    if asset_class not in valid_assets:
        raise ValueError(f"无效资产类型，可选值：{valid_assets}")

    # 定义验证条件阈值
    validation_rules = {
        "外汇": {
            "required_metrics": ["sharpe", "max_dd", "win_rate"],
            "conditions": lambda m: (
                    m.get("sharpe", 0) > 1.5 and
                    m.get("max_dd", 0) > -0.15 and  # 注意max_dd是负数
                    m.get("win_rate", 0) > 0.6
            )
        },
        "国债": {
            "required_metrics": ["sharpe", "volatility", "carry_return"],
            "conditions": lambda m: (
                    m.get("sharpe", 0) > 1.2 and
                    m.get("volatility", 1) < 0.1 and  # 默认高波动视为不通过
                    m.get("carry_return", 0) > 0.1
            )
        },
        "政策性金融债": {
            "required_metrics": ["sharpe", "volatility", "carry_return"],
            "conditions": lambda m: (
                    m.get("sharpe", 0) > 1.1 and
                    m.get("volatility", 1) < 0.15 and
                    m.get("carry_return", 0) > 0.08
            )
        }
    }

    # 获取当前资产类型的验证规则
    rules = validation_rules[asset_class]

    # 遍历所有因子进行验证
    for factor, metrics in backtest_report.items():
        try:
            # 检查必须的指标是否存在
            if not all(k in metrics for k in rules["required_metrics"]):
                continue

            # 执行验证条件判断
            if rules["conditions"](metrics):
                return True

        except (TypeError, KeyError) as e:
            print(f"因子 {factor} 验证异常: {str(e)}")
            continue

    return False




class DrawdownMonitor:
    """实时回撤追踪"""

    def __init__(self):
        self.peak = -np.inf
        self.max_dd = 0

    def update(self, current_val):
        self.peak = max(self.peak, current_val)
        self.max_dd = min(self.max_dd, current_val / self.peak - 1)
        return self.max_dd


